package org.nw.service.sys.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;

import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.SuperVO;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.util.IOUtils;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.nw.constants.Constants;
import org.nw.dao.NWDao;
import org.nw.exception.BusiException;
import org.nw.service.impl.AbsToftServiceImpl;
import org.nw.service.sys.FilesystemService;
import org.nw.vo.HYBillVO;
import org.nw.vo.ParamVO;
import org.nw.vo.VOTableVO;
import org.nw.vo.sys.FilesystemVO;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.stereotype.Service;

/**
 * 
 * @author xuqc
 * @date 2013-8-12 下午09:56:28
 */
@Service
public class FilesystemServiceImpl extends AbsToftServiceImpl implements FilesystemService {

	AggregatedValueObject billInfo = null;

	public AggregatedValueObject getBillInfo() {
		if(billInfo == null) {
			billInfo = new HYBillVO();
			VOTableVO vo = new VOTableVO();
			vo.setAttributeValue(VOTableVO.BILLVO, HYBillVO.class.getName());
			vo.setAttributeValue(VOTableVO.HEADITEMVO, FilesystemVO.class.getName());
			vo.setAttributeValue(VOTableVO.PKFIELD, FilesystemVO.PK_FILESYSTEM);
			billInfo.setParentVO(vo);
		}
		return billInfo;
	}

	@Override
	public String buildLoadDataOrderBy(ParamVO paramVO, Class<? extends SuperVO> clazz, String orderBy) {
		orderBy = super.buildLoadDataOrderBy(paramVO, clazz, orderBy);
		if(StringUtils.isBlank(orderBy)) {
			return " order by ts";
		}
		return orderBy;
	}

	/**
	 * 文件表比较大，使用物理删除
	 */
	protected boolean isLogicalDelete() {
		return false;
	}

	@Override
	public String[] getLoadDataFields() {
		return new String[] { "pk_filesystem", "dr", "ts", "billtype", "pk_bill", "file_name", "file_size",
				"folder_flag", "parent_id", "md5", "create_user", "create_time" };
	}

	public void upload(final FilesystemVO attachVO, final InputStream in) {
		NWDao dao = NWDao.getInstance();
		String sql = "insert into nw_filesystem(pk_filesystem, dr,ts,billtype,pk_bill,folder_flag,file_name,file_size, parent_id,md5,create_user,create_time,contentdata) "
				+ "values(?,?,?,?,?,?,?,?,?,?,?,?,?)";
		dao.getJdbcTemplate().execute(sql, new PreparedStatementCallback<FilesystemVO>() {
			public FilesystemVO doInPreparedStatement(PreparedStatement ps) throws SQLException {
				ps.setObject(1, attachVO.getPk_filesystem());
				ps.setObject(2, attachVO.getDr());
				ps.setObject(3, attachVO.getTs().toString());
				ps.setObject(4, attachVO.getBilltype());
				ps.setObject(5, attachVO.getPk_bill());
				ps.setObject(6, attachVO.getFolder_flag());
				ps.setObject(7, attachVO.getFile_name());
				ps.setObject(8, attachVO.getFile_size());
				ps.setObject(9, attachVO.getParent_id());
				ps.setObject(10, attachVO.getMd5());
				ps.setObject(11, attachVO.getCreate_user());
				ps.setObject(12, attachVO.getCreate_time().toString());
				ps.setBinaryStream(13, in, attachVO.getFile_size().intValue());
				ps.execute();
				return attachVO;
			}
		});
	}

	public void upload(final List<FilesystemVO> attachVOs, final List<InputStream> inAry) {
		if(attachVOs == null || inAry == null) {
			return;
		}
		for(int i = 0; i < attachVOs.size(); i++) {
			upload(attachVOs.get(i), inAry.get(i));
		}
	}

	public FilesystemVO getByPrimaryKey(String primaryKey) {
		String sql = "select pk_filesystem, dr,ts,billtype,pk_bill,folder_flag,file_name,file_size,parent_id,md5,create_user,create_time "
				+ "from nw_filesystem where pk_filesystem=?";
		return NWDao.getInstance().getJdbcTemplate()
				.queryForObject(sql, new String[] { primaryKey }, new FilesystemRowMapper());
	}

	@SuppressWarnings({ "rawtypes" })
	public void download(String pk_filesystem, OutputStream out) throws Exception {
		String sql = "select contentdata from nw_filesystem where pk_filesystem=?";
		HashMap retMap = NWDao.getInstance().queryForObject(sql, HashMap.class, pk_filesystem);
		if(retMap == null) {
			logger.warn("您下载的文件已经不存在,pk_filesystem=" + pk_filesystem);
			throw new BusiException("您下载的文件已经不存在，请刷新页面！");
		}
		Object contentdata = retMap.get("contentdata");
		if(contentdata != null) {
			InputStream in = (InputStream) contentdata;
			IOUtils.copy(in, out);
		}
	}

	@SuppressWarnings("rawtypes")
	public void zipDownload(String[] pk_filesystem, OutputStream out) {
		String tmpdirPath = Constants.TMPDIR;
		File tmpdir = new File(tmpdirPath);
		if(!tmpdir.exists()) {
			tmpdir.mkdir();
		}
		for(String pk : pk_filesystem) {
			String sql = "select file_name,contentdata from nw_filesystem where pk_filesystem=?";
			HashMap retMap = NWDao.getInstance().queryForObject(sql, HashMap.class, pk);
			if(retMap == null) {
				logger.warn("您下载的文件已经不存在,pk_filesystem=" + pk);
				continue;
			}
			String file_name = retMap.get("file_name").toString();// 文件名称
			File file = new File(tmpdirPath + File.separator + file_name);// 创建一个用于存储数据库文件的临时文件
			InputStream in = (InputStream) retMap.get("contentdata"); // 从数据库中读取了inputstream，写入临时文件中
			FileOutputStream fos = null;
			try {
				fos = new FileOutputStream(file);
				byte[] b = new byte[1024];
				int readLength;
				while((readLength = in.read(b)) != -1) {
					fos.write(b, 0, readLength);
				}
			} catch(Exception e) {
				logger.error(e.getMessage());
				e.printStackTrace();
			} finally {
				try {
					if(fos != null) {
						fos.flush();
						fos.close();
					}
					if(in != null) {
						in.close();
					}
				} catch(IOException e) {
					e.printStackTrace();
				}
			}
		}
		zipFile(tmpdir, out, "");
		try {
			FileUtils.deleteDirectory(tmpdir);// 删除临时文件
		} catch(IOException e) {
			logger.error("删除临时目录错误：" + e.getMessage());
		}
	}

	/**
	 * 文件夹打包下载
	 * 
	 * @param dir
	 * @param zipOut
	 * @param parent
	 * @author xuqc
	 * @date 2012-10-17
	 * 
	 */
	private void zipFile(File dir, OutputStream out, String parent) {
		ZipOutputStream zipOut = new ZipOutputStream(out);
		zipOut.setEncoding("GBK");
		if(!dir.isDirectory()) {
			throw new BusiException(dir.getName() + "不是一个文件夹！");
		}
		// 写入压缩流
		try {
			for(File file : dir.listFiles()) {
				if(file.isFile()) {
					// 文件
					ZipEntry zipEntry = new ZipEntry(parent + file.getName());
					zipOut.putNextEntry(zipEntry);
					FileInputStream in = new FileInputStream(file);
					byte[] b = new byte[1024];
					int readLength;
					while((readLength = in.read(b)) != -1) {
						zipOut.write(b, 0, readLength);
					}
					zipOut.closeEntry();
					in.close();
				} else {
					// 目录
					zipFile(file, zipOut, file.getName() + File.separator);
				}
			}
		} catch(Exception e) {
			logger.error("生成压缩文件出错:" + e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				zipOut.close();
			} catch(IOException e) {
				e.printStackTrace();
			}
		}
	}
}
